package com.wdb007.venus.web.api.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wdb007.venus.svc.facade.UserService;
import com.wdb007.venus.svc.facade.constant.BizConstants;
import com.wdb007.venus.svc.facade.constant.RspCodeEnum;
import com.wdb007.venus.svc.facade.exception.BizException;
import com.wdb007.venus.svc.facade.exception.SysException;
import com.wdb007.venus.svc.facade.user.model.UserInfoDTO;
import com.wdb007.venus.web.api.Jsonable;
import com.wdb007.venus.web.api.model.BaseResponse;
import com.wdb007.venus.web.api.utils.MD5Util;

@Component
public class UserTokenFilter implements Filter{

	private static final Logger logger = LoggerFactory.getLogger(UserTokenFilter.class);
	
	@Autowired
	private UserService userService;
	
	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String url = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
		logger.info("请求路径: " + url);
		try {
			String useridstr = httpRequest.getParameter("userid");
			String usertoken = httpRequest.getParameter("usertoken");
			String channelStr = httpRequest.getHeader("source");
			String headerToken = httpRequest.getHeader("token");

			Byte channel = BizConstants.CHANNEL_APP;
			if(!ObjectUtils.isEmpty(channelStr)) {
				if(channelStr.equals("wx_app")) {
					channel = BizConstants.CHANNEL_WX;
				}
			}
			
			if(ObjectUtils.isEmpty(useridstr)) {
				throw new BizException(RspCodeEnum.USER_ID_IS_NULL);
			}
			if(ObjectUtils.isEmpty(usertoken)) {
				if(ObjectUtils.isEmpty(headerToken)) {
					throw new BizException(RspCodeEnum.TOKEN_IS_NULL);
				}
			}
			logger.info("usertoken: {}", usertoken);
			logger.info("userid: {}", useridstr);
			Long userid = Long.valueOf(useridstr);
			UserInfoDTO userInfo = userService.get(userid);
			logger.info("logInfoDTO: {}", JSON.toJSONString(userInfo));
			if(null == userInfo) {
				throw new BizException(RspCodeEnum.OBJ_NOT_FOUND.setRspMessage("用户"));
			}
			if(usertoken.equals(userInfo.getUsertoken())) {	//如果相同
				//判断过期
				Date token_generate_time = userInfo.getTokenGenerateTime();
				if(isExpired(token_generate_time)) {	//已经过期
					
					if(!ObjectUtils.isEmpty(userInfo.getNewUsertoken())) {	//如果库中存在新的token。
						Integer expireTimes = userInfo.getTokenExpireTimes();
						if(expireTimes <= 5) {
							userInfo.setTokenExpireTimes(++expireTimes);
							userService.update(userInfo);
							chain.doFilter(httpRequest, httpResponse);
						}else {
							//token验证失败
							throw new BizException(RspCodeEnum.USER_TOKEN_IS_UNVALID);
						}
					}else {		//如果库中不存在new_token, 则产生新的usertoken
						String token = MD5Util.generateToken();
						userInfo.setNewUsertoken(token);
						userInfo.setTokenExpireTimes(0);
						userInfo.setTokenGenerateTime(new Date());
						userService.update(userInfo);
						chain.doFilter(httpRequest, httpResponse);
					}
				}else {				
					//不过期
					chain.doFilter(httpRequest, httpResponse);
				}
			}else {	//不相同
				String new_token = userInfo.getNewUsertoken();
				if(usertoken.equals(new_token)) {
					userInfo.setUsertoken(new_token);
					userInfo.setNewUsertoken(null);
					userInfo.setTokenExpireTimes(0);
					userService.update(userInfo);
					chain.doFilter(httpRequest, httpResponse);
				} else {
					// 判断是否为微信
					String wxtoken = userService.getTokenByChannelAndUserId(userid, channel);
					// headerToken 为空表示在 app中 利用usertoken比较
					if (ObjectUtils.isEmpty(headerToken)) {
						headerToken = usertoken;
					}
					if (!headerToken.equals(wxtoken)) {
						throw new BizException(RspCodeEnum.USER_TOKEN_IS_UNVALID);
					} else {
						chain.doFilter(httpRequest, httpResponse);
					}

				}
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			BaseResponse<Jsonable> res = new BaseResponse();
			res.setResult(0);
			if(e instanceof BizException) {
				BizException bizRuntimeException = (BizException) e;
				res.setCode(bizRuntimeException.getErrorCode());
				res.setMessage(bizRuntimeException.getErrorMsg());
			}else if(e instanceof SysException) {
				SysException sysRuntimeException = (SysException) e;
				res.setCode(sysRuntimeException.getErrorCode());
				res.setMessage(sysRuntimeException.getErrorMsg());
			}else {
				res.setCode(1010080099);
				res.setMessage("系统异常，请联系管理员");
			}
			responseOutWithJson(httpResponse, res);
		}
	}

	private void responseOutWithJson(HttpServletResponse httpResponse, Object response) {
		JSONObject jsonObject = (JSONObject) JSON.toJSON(response);
		httpResponse.setCharacterEncoding("UTF-8");
		httpResponse.setContentType("application/json; charset=utf-8");  
		PrintWriter out = null;  
	    try {  
	        out = httpResponse.getWriter();  
	        out.append(jsonObject.toString());  
	        logger.debug(jsonObject.toString());  
	        out.flush();
	    } catch (IOException e) {  
	        e.printStackTrace();  
	    } finally {  
	        if (out != null) {  
	        }  
	    }  
	}
	
	private boolean isExpired(Date token_generate_time) {
		Date now = new Date();
		int hours = (int) ((now.getTime() - token_generate_time.getTime()) / 1000 / 3600) ;
		return hours >= 24*7 ;
	}
	@Override
	public void init(FilterConfig arg0) throws ServletException {
		
	}

}
